import asyncio
import json
import logging
import pathlib
import shutil
import uuid

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.UrlToImage import url_img_docx
from app.common.AiUtils import AiCli, AsyncAiCli
from app.common.DocxUtils import render_docx
from app.common.StandPrompts import sys_list_prompt, appconfig_prompt, create_application_from, \
    create_source_code_prompt, create_backend_foundation_prompt, create_backend_logic_prompt, \
    create_frontend_component_prompt
from app.core.response.ResponseResult import ResponseResult
from app.db import SoftwareCopyrightCurd
from app.db.DBConfig import get_db, get_db_context
from app.db.SoftCopyrightDB import SoftCopyrightDB
from app.db.SoftwareCopyrightCurd import add_sc, update_sc
from app.dto.DocToPDF import convert_docx_to_pdf
from app.dto.GaiDto import FeatureListDto, AppConfigDto, TeDto, PageDto
from app.utils.JsonCleanUtils import parse_ai_json_string, validate_json_keys

tem_path = "temp_static"
tem_url_path = "temp_static"
tem_url = "http://zl.sunne.xyz"
# "http://zl.sunne.xyz/temp_stactic/8a9c3729-7744-4546-8bf4-a9af5ec74e09/index.html#pets/edit/101"
router = APIRouter(prefix="/gai", tags=["gm"])
tasks_storage = {}

required_fields = [
    "sys_name", "dev_environment", "prod_environment", "dev_tools",
    "running_sys", "software_support_environment", "programming_language",
    "number_code", "purpose", "field_oriented", "main_functions",
    "classification", "technical_features"
]

@router.post("/create_feature_list", summary="生成功能列表", description="根据用户需求生成10~15个功能")
async def create_feature_list(fls:FeatureListDto,db: AsyncSession = Depends(get_db)):
    prompt_u = sys_list_prompt(fls.sys_name,amount=fls.amount)
    # result = generate(prompt_u)
    message=[
        {"role": "user", "content": prompt_u}
    ]
    sc_id = str(uuid.uuid4())
    result = await AiCli(messages=message,user=sc_id,max_tokens=8096)
    list_data = parse_ai_json_string(result)
    sc = SoftCopyrightDB(
        id=sc_id,
        system_name=fls.sys_name,
        tech_stack=fls.tech_stack
    )
    await add_sc(db, sc)
    sc_info = {
        "sc_id":sc_id,
        "sys_name": fls.sys_name,
        "feature_list": list_data,
        "tech_stack":fls.tech_stack
    }
    return ResponseResult.ok_data(data=sc_info)

@router.post("/create_app", summary="生成页面功能", description="根据用户的最终list功能列表生成完整的功能")
async def create_feature_list_by_file(app_config:AppConfigDto, ):
    # async with get_db_context() as db_session:
        #将所有任务全部挂在后台
    taskaid=str(uuid.uuid4())
    asyncio.create_task(generate_all_task(taskaid, app_config))
    return ResponseResult.ok_data(data={"task_id": taskaid})



#查看生成的所有软著信息
@router.post("/get_all_sc", summary="查看所有软著信息")
async def get_all_sc(pd:PageDto,db: AsyncSession = Depends(get_db)):
    sc_list = await SoftwareCopyrightCurd.get_all_sc(db, page_num=pd.page_num, page_size=pd.page_size)
    return ResponseResult.ok_data(data=sc_list)

async def generate_all_task(taskaid:str,app_config:AppConfigDto):
    async with get_db_context() as db:
        tasks_storage[taskaid] = {
            "status": "running",
            "data": "任务已经开始",
            "error": None,
            "progress": f"{0 * 100:.1f}%"
        }
        prompt_u = appconfig_prompt(app_config.sys_name, app_config.feature_list)
        # result = generate(prompt_u)
        uid_path = str(uuid.uuid4())
        message = [
            {"role": "user", "content": prompt_u}
        ]
        result = await AiCli(messages=message, user=uid_path, max_tokens=8096)
        list_data = parse_ai_json_string(result)
        # uuid 生成uuid并且记录对应的菜单，适配预览路由
        # 开始记录功能和详细配置
        sc = {
            "id": app_config.sc_id,
            "system_name": app_config.sys_name,
            "feature_list": app_config.feature_list,
            "config_data": list_data,
            "status": False
        }

        await update_sc(db, app_config.sc_id, sc)
        tasks_storage[taskaid] = {
            "status": "running",
            "data": "已经完成appconfig.js编写",
            "error": None,
            "progress": f"{0.15 * 100:.1f}%"
        }
        config_path = f"{tem_path}/{app_config.sc_id}/config.js"
        # 母文件所在位置
        source_index = f"{tem_path}/index.html"
        destination_dir = f"{tem_path}/{app_config.sc_id}/index.html"
        json_string = json.dumps(list_data, indent=4, ensure_ascii=False)
        js_content = f"""const AppConfig = {json_string};"""
        pathlib.Path(config_path).parent.mkdir(parents=True, exist_ok=True)
        try:
            with open(config_path, 'w', encoding='utf-8') as f:
                f.write(js_content)
            shutil.copy(source_index, destination_dir)
            print(f"成功将数据写入到文件: {config_path}")
            print(f"成功复制文件: {destination_dir}")
        except IOError as e:
            print(f"写入文件时发生错误: {e}")
        # 系统文件写入完毕，并且部署到了对应的路径下
        sc_conf = {
            "id": app_config.sc_id,
            "config_data": json_string
        }
        await update_sc(db, app_config.sc_id, sc_conf)
        # 开始写材料
        tasks_storage[taskaid] = {
            "status": "running",
            "data": "已经完成appconfig.js编写",
            "error": None,
            "progress": f"{0.65 * 100:.1f}%"
        }
        new_task_id = str(uuid.uuid4())
        rf = await create_full_sc(new_task_id,app_config, db)
        tasks_storage[taskaid] = {
            "status": "running",
            "data": "已经完成appconfig.js编写",
            "error": None,
            "progress": f"{1.0 * 100:.1f}%"
        }
    return ResponseResult.ok_data(data=rf)


async def create_full_sc(all_task_id:str,config:AppConfigDto,db):
    #获得基础信息
    sc =await SoftwareCopyrightCurd.get_sc_by_id(db,sc_id=config.sc_id)
    #开始写申请表
    logging.info("开始写申请表")
    app_from_prompt = create_application_from(sys_name=sc.system_name, feature_list=sc.feature_list, tech_stack=sc.tech_stack)
    message=[
        {"role": "user", "content": app_from_prompt}
    ]
    app_from = await AiCli(messages=message, user=str(uuid.uuid4()), max_tokens=8096)
    app_from = parse_ai_json_string(app_from)
    logging.info("申请表处理完成")
    is_valid, result = validate_json_keys(json_input=app_from,required_keys=required_fields)
    if not is_valid:
        print(f"缺少以下字段: {result}")
        return False
    doc_stream = render_docx(f"{tem_path}/xxx_application_from.docx",app_from )
    app_from_doc = f"{tem_path}/{sc.id}/{sc.system_name}申请表.docx"
    pathlib.Path(f"{tem_path}/{sc.id}").mkdir(parents=True, exist_ok=True)
    with open(app_from_doc, 'wb') as f:
        f.write(doc_stream.getvalue())
    #软著申请表下载链接
    app_from_doc_url = f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}申请表.docx"
    #开始写操作手册
    data_dict = json.loads(sc.config_data)
    task_doc_info = generate_document_tasks(sc.id, sc.feature_list,data_dict)
    logging.info(f"开始写操作手册：{task_doc_info}")
    operation_doc = f"{tem_path}/{sc.id}/{sc.system_name}操作手册.docx"
    url_img_docx(sc_id=sc.id,task_doc_info=task_doc_info,title=sc.system_name,out_put_path=operation_doc)
    operation_doc_url = f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}操作手册.docx"
    #生成源码文档
    sc_td = TeDto(system_name="",feature_list=[],tech_stack="",id=sc.id)
    task_id = str(uuid.uuid4())
    sources_doc = f"{tem_path}/{sc.id}/{sc.system_name}代码文档.docx"
    sources_doc_url = f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}代码文档.docx"
    preview_url = f"{tem_url}/{tem_url_path}/{sc.id}/index.html"
    operation_pdf = f"{tem_path}/{sc.id}/{sc.system_name}操作手册.pdf"
    app_from_pdf = f"{tem_path}/{sc.id}/{sc.system_name}申请表.pdf"
    #转换成PDF
    logging.info(f"开始转换成PDF：{operation_pdf}")
    logging.info(f"开始转换成PDF：{app_from_pdf}")
    convert_docx_to_pdf(operation_doc,operation_pdf)
    convert_docx_to_pdf(app_from_doc,app_from_pdf)
    # await generate_architecture_task(task_id,sc_td,sources_doc_path=sources_doc,
    #                                  app_from_doc_url=app_from_doc_url,operation_doc_url=operation_doc_url,
    #                                  sources_doc_url=sources_doc_url,preview_url=preview_url,db=db)
    source_code = await split_task(system_name=sc.system_name,feature_list=sc.feature_list,tech_stack=sc.tech_stack)
    sources_pdf = f"{tem_path}/{sc.id}/{sc.system_name}代码文档.pdf"
    try:
        with open(sources_doc, 'w', encoding='utf-8') as f:
            f.write(source_code)
    except IOError as e:
        print(f"写入文件时发生错误: {e}")
    convert_docx_to_pdf(sources_doc, sources_pdf)
    sc_info = {
        "introduction_doc": app_from_doc_url,
        "introduction_pdf": f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}申请表.pdf",
        "operation_doc": operation_doc_url,
        "operation_pdf": f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}操作手册.pdf",
        "code_doc": sources_doc_url,
        "code_pdf": f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}代码文档.pdf",
        "preview_url": preview_url
    }
    await update_sc(db, sc.id, sc_info)
    return ResponseResult.ok_data(data={"当前任务id": all_task_id})


@router.get("/architecture/task/{task_id}", summary="查询生成任务状态")
async def get_task_status(task_id: str):
    task_info = tasks_storage.get(task_id)
    if not task_info:
        return ResponseResult.error(message="任务不存在")

    return ResponseResult.ok_data(data=task_info)
def generate_document_tasks(project_uuid, feature_list, config_data):
    """
    根据所有输入信息，生成用于文档自动化的、高度结构化的任务列表。
    """
    doc_tasks = []
    base_url = f"{tem_url}/{tem_url_path}/{project_uuid}/index.html"

    # 创建一个从 feature name 到 description 的快速查找字典
    feature_desc_map = {item['name']: item['description'] for item in feature_list}

    # 遍历config中的菜单
    for menu_item in config_data['menu']:
        feature_id = menu_item['id']
        feature_name = menu_item['name']
        feature_desc = feature_desc_map.get(feature_name, "")

        feature_data = config_data['data'].get(feature_id, {})

        # 任务1: 新增 (add)
        doc_tasks.append({
            "url_path": f"{base_url}#{feature_id}/add",
            "feature_name": feature_name,
            "feature_description": feature_desc,
            "action_type": "add",
            "action_description": f"对【{feature_name}】模块进行新增操作的界面。"
        })

        # 任务2 & 3: 遍历数据行，生成编辑(edit)和删除(delete)任务
        rows = feature_data.get('rows', [])
        columns = feature_data.get('columns', [])
        primary_key = columns[0]['key'] if columns else None

        for row_item in rows:
            item_id = row_item.get('id')
            if not item_id: continue
            item_name = row_item.get(primary_key, f"ID {item_id}") if primary_key else f"ID {item_id}"
            # 编辑任务
            doc_tasks.append({
                "url_path": f"{base_url}#{feature_id}/edit/{item_id}",
                "feature_name": feature_name,
                "feature_description": feature_desc,
                "action_type": "edit",
                "action_description": f"对记录“{item_name}”进行编辑操作的界面。"
            })

            # 删除任务
            doc_tasks.append({
                "url_path": f"{base_url}#{feature_id}/delete/{item_id}",
                "feature_name": feature_name,
                "feature_description": feature_desc,
                "action_type": "delete",
                "action_description": f"对记录“{item_name}”进行删除操作的确认界面。"
            })
    return doc_tasks

async def split_task(system_name, feature_list:list, tech_stack):
    uid_mes = str(uuid.uuid4())
    tasks = []
    for round_index in range(2):
        for feature in feature_list:
            feature_name = feature['name']
            feature_desc = feature['description']
            # 创建后端任务
            back_prompt = create_backend_foundation_prompt(feature_name, system_name,feature_desc,tech_stack)
            back_message = [
                {"role": "user", "content": back_prompt}
            ]
            tasks.append(AsyncAiCli(back_message,user=uid_mes))

            backend_logic_prompt = create_backend_logic_prompt(feature_name, system_name,feature_desc,tech_stack)
            backend_logic_message = [
                {"role": "user", "content": backend_logic_prompt}
            ]
            tasks.append(AsyncAiCli(backend_logic_message,user=uid_mes))
            # 创建前端任务
            front_prompt = create_frontend_component_prompt(feature_name, system_name,feature_desc,tech_stack)
            front_message = [
                {"role": "user", "content": front_prompt}
            ]
            tasks.append(AsyncAiCli(front_message,user=uid_mes))
    print(f"共创建 {len(tasks)} 个代码生成任务，开始并行执行...")
    results = await asyncio.gather(*tasks)
    final_code_list = []
    for res in results:
        final_code_list.append(res)
    full_source_code = "\n\n".join(final_code_list)
    return full_source_code


async def generate_architecture_task(task_id: str, sc: TeDto,sources_doc_path, app_from_doc_url,operation_doc_url,
                                     sources_doc_url,preview_url,db):
    try:
        sources_prompt = create_source_code_prompt(
            sys_name=sc.system_name,
            feature_list=sc.feature_list,
            tech_stack=sc.tech_stack
        )
        sources_message = [
            {"role": "user", "content": sources_prompt}
        ]

        final_code_list = []
        full_source_code = ""

        # 循环生成直到内容长度满足要求
        while len(full_source_code) < 60000:
            print("开始生成系统架构...")
            tasks_storage[task_id] = {
                "status": "processing",
                "data": f"已生成字符数: {len(full_source_code)}，任务为非流式，不统计详细细节，如果字数未0说明第一轮尚未完成，请耐心等待...",
                "error": None,
                "progress": f"{len(full_source_code) / 60000 * 100:.1f}%"
            }
            app_from = await AiCli(
                messages=sources_message,
                user=str(uuid.uuid4()),
                max_tokens=8192
            )
            final_code_list.append(app_from)
            full_source_code = "\n\n".join(final_code_list)
            # 如果长度还不够，继续生成
            if len(full_source_code) < 60000:
                app_from2 = await AiCli(
                    messages=sources_message,
                    user=str(uuid.uuid4()),
                    max_tokens=8192
                )
                final_code_list.append(app_from2)
                full_source_code = "\n\n".join(final_code_list)

        # 写入文档
        with open(sources_doc_path, 'w', encoding="utf-8") as f:
            f.write(full_source_code)
        # 更新任务状态为完成
        tasks_storage[task_id] = {
            "status": "completed",
            "data": sources_doc_path,
            "error": None,
            "progress": f"{len(full_source_code) / 60000 * 100:.1f}%"
        }
        sources_pdf =  f"{tem_path}/{sc.id}/{sc.system_name}代码文档.pdf"
        convert_docx_to_pdf(sources_doc_path, sources_pdf)
        sc_info = {
            "id": sc.id,
            "introduction_doc": app_from_doc_url,
            "introduction_pdf":f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}申请表.pdf",
            "operation_doc": operation_doc_url,
            "operation_pdf":"operation_pdf",
            "code_doc": f"{tem_url}/{tem_url_path}/{sc.id}/{sc.system_name}操作手册.pdf",
            "code_pdf":sources_pdf,
            "preview_url": preview_url
        }
        await update_sc(db, sc.id, sc_info)
    except Exception as e:
        # 更新任务状态为失败
        tasks_storage[task_id] = {
            "status": "failed",
            "data": None,
            "error": str(e)
        }
